// connections: windowId:tabId
const connectionsMap = {};
const connectionBoundMap = {};
const actionsMap = {
	mid: 0,
	mCounter: 0,
	portName: 'backend:' + new Date().getTime(),
	acceptNewPort: function(newPort){
		console.log('new port connection from: ' + newPort.name);
		console.log(newPort);
		let self = this;
		let portName = newPort.name;
		let portTabUrl = newPort.sender.tab.url;
		if(!portTabUrl.startsWith('devtools://')){ // TODO identify special tab urls only for dev tool pages
			self.boundPort(portName, newPort.sender.tab.id);
		}
		connectionsMap[portName] = newPort;
		newPort.onDisconnect.addListener((from) => {
			console.log('connection closed: ' + from.name);
			connectionsMap[from.name] = null;
			delete connectionsMap[from.name];
		});
		newPort.onMessage.addListener((msg, src) => {
			//console.log('receive connection message: ' + JSON.stringify({type: msg.type, name: msg.data.name, sid: msg.sid}));
			actionsMap.handlePortMsg(msg, {port: newPort});
		});

	},

	boundPort: function(portName, portTabId){
		let self = this;
		let portType = portName.split(':')[0];
		let tabPortsBound = connectionBoundMap[portTabId];
		if(null == tabPortsBound){
			connectionBoundMap[portTabId] = {};
			tabPortsBound = connectionBoundMap[portTabId];
		}
		tabPortsBound[portType] = portName;
		console.log(connectionBoundMap);

	},
	
	handlePortMsg: function(msg, context){
		//console.log({type: 'print', data: {msg: msg, context: context}});
		let self = this;
		let type = msg.type;
		let from = msg.from;
		let name = msg.data.name;
		if('event' == type){
			if('ping' == name && 'content' == from){
				let pongMsg = {type: 'event', data: {name: 'pong', data: context.port.sender.tab.id}};
				self.sendMessage(pongMsg, context.port);
				return;
			}
			if('ping' == name && 'crawler' == from){
				if(!msg.data.data){
					console.log({type: 'unknown', msg: msg, context: context});
					return;
				}
				self.boundPort(context.port.name, msg.data.data);
				let pongMsg = {type: 'event', data: {name: 'pong', data: msg.data.data}};
				self.sendMessage(pongMsg, context.port);
				return;
			}
			if('nodeSnapshotUpdated' == name){
				self.sendPortMsg(msg, 'crawler');
				return;
			}
		}
		if('cmd' == type){
			if('menu' == name){
				menuActions.exeMenuOpt(msg);
				return;
			}
			if('action' == name){
				menuActions.executeActionOpt(msg);
				return;
			}
			self.sendPortMsg(msg, 'content');
			return;
		}
		if('cmd-resp' == type){
			self.sendPortMsg(msg, 'crawler');
			return;
		}

	},
	
	sendPortMsg: function(msg, portType){
		let self = this;
		let tabId = msg.tid;
		let tabPorts = connectionBoundMap[tabId];
		if(null == tabPorts){
			console.log({type: 'error', data: {msg: msg, portType: portType}});
			return;
		}
		let portName = tabPorts[portType];
		let destPortRef = connectionsMap[portName];
		if(null == portName || null == destPortRef){
			//console.log('connection not exists, discard forward: ' + JSON.stringify({sid: msg.sid, destPortType: portType}));
			return;
		}
		self.sendMessage(msg, destPortRef);

	},
	
	sendMessage: function(msgInfo, targetPort){
		let self = this;
		if(0 == self.mid){
			self.mid = new Date().getTime();
		}
		self.mCounter = self.mCounter + 1;
		msgInfo.sid = 'backend:' + self.mid + self.mCounter;
		msgInfo.from = 'backend';
		msgInfo.sender = self.portName;
		targetPort.postMessage(msgInfo);

	},

	printSelf: function(){
		if(chrome.windows){
			chrome.windows.getCurrent({}, function(win){
				console.log(win);
			});
			chrome.windows.getAll(function(wins){
				console.log(wins);
			});
		}

		if(chrome.tabs){
			chrome.tabs.getCurrent(function(tab){
				console.log(tab);
			});
			chrome.tabs.query({}, function(tabs){
				console.log(tabs);
			});			
		}

	},
	
	alarmName: 'backend-alive-keeper',
	startAliveKeeper: function(){
		let self = this;
		chrome.alarms.clear(self.alarmName, function(cleared){
			console.log('try clear old backend alive keeper: ' + cleared);
		});
		chrome.alarms.create(self.alarmName, {periodInMinutes: 0.5});
		chrome.alarms.onAlarm.addListener(function(alarm){
			for(var key in connectionsMap){
				let portRef = connectionsMap[key];
				let hearBeatMsg = {type: 'event', data: {name: 'heartBeat'}};
				self.sendMessage(hearBeatMsg, portRef);
			}
		});

	},

};

const menuActions = {
	exeMenuOpt: function(cmdMsg){
		console.log('excute menu opt');
		console.log(cmdMsg);
		let self = this;
		let menuMsg = cmdMsg.data.data;
		let type = menuMsg.opt;
		let menu = menuMsg.menu;
		if('add' == type){
			chrome.contextMenus.create(menu, function(){self.handleActionFinish(menuMsg)});
			return;
		}
		if('del' == type){
			chrome.contextMenus.remove(menu, function(){self.handleActionFinish(menuMsg)});
			return;
		}
		if('update' == type){
			chrome.contextMenus.update(menu, function(){self.handleActionFinish(menuMsg)});
			return;
		}

	},

	executeActionOpt: function(cmdMsg){
		let self = this;
		let actionOpt = cmdMsg.data.data;
		let type = actionOpt.type;
		let badgeTextInfo = {tabId: cmdMsg.tid, text: 'on'};
		let badgeBgColorInfo = {tabId: cmdMsg.tid, color: actionOpt.color};
		if('disable' == type){
			badgeTextInfo = {tabId: cmdMsg.tid, text: 'off'};
			badgeBgColorInfo = {tabId: cmdMsg.tid, color: 'gray'};
		}
		chrome.action.setBadgeText(badgeTextInfo, self.handleActionFinish(cmdMsg));
		chrome.action.setBadgeBackgroundColor(badgeBgColorInfo, self.handleActionFinish(cmdMsg));

	},

	handleActionFinish: function(menuMsg) {
		console.log(menuMsg);
		let self = this;

	},

	handleMenuClick: function(clickInfo){
		console.log(clickInfo);
		let self = this;
		let menuClickMsg = {type: 'event', tid: clickInfo.tab.id, data: {name: 'menuClick', data: {menu: clickInfo.menu}}};
		actionsMap.sendPortMsg(menuClickMsg, 'content');

	},

	handleActionClick: function(tab){
		console.log(tab);
		let self = this;
		let clickMsg = {type: 'event', tid: tab.id, data: {name: 'actionClick'}};
		actionsMap.sendPortMsg(clickMsg, 'content');

	},



};

const crawler = {
	registerChromeListener: function(){
		chrome.action.onClicked.addListener(function(tab){
			menuActions.handleActionClick(tab);
		});
		chrome.contextMenus.onClicked.addListener(function(menu, tab){
			self.handleMenuClick({menu: menu, tab: tab});
		});
		chrome.runtime.onConnect.addListener(function(port){
			actionsMap.acceptNewPort(port);
		});
		chrome.runtime.onMessage.addListener(function(msg, sender, callback){
			console.log('back ground receive annoymouse message: ' + JSON.stringify({msg: msg, sender: sender, callback: callback}));
		});

	}

};

actionsMap.printSelf();
crawler.registerChromeListener();